#include "DHT11.h"

/**
 * 设置总线为输出模式
 */
void DHT11_Init_Out(){														
	DHT11_RCC_APBClkCmd(DHT11_GPIO_CLK,ENABLE);			//开启时钟
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;			//设置推挽输出模式
	GPIO_InitStruct.GPIO_Pin=DHT11_GPIO_Pin;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(DHT11_GPIO_PORT,&GPIO_InitStruct);
}

/**
 * 设置总线为输入模式
 */
void DHT11_Init_In(){
	DHT11_RCC_APBClkCmd(DHT11_GPIO_CLK,ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;	//设置浮空输入模式
	GPIO_InitStruct.GPIO_Pin=DHT11_GPIO_Pin;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(DHT11_GPIO_PORT,&GPIO_InitStruct);
}

void DHT11_High(){
	GPIO_SetBits(DHT11_GPIO_PORT,DHT11_GPIO_Pin);
}

void DHT11_Low(){
	GPIO_ResetBits(DHT11_GPIO_PORT,DHT11_GPIO_Pin);
}

uint8_t DHT11_GPIO_Read(void){
	return GPIO_ReadInputDataBit(DHT11_GPIO_PORT,DHT11_GPIO_Pin);
}

/**
 * 初始化DHT11
 */
void DHT11_Init(){
	DHT11_Init_Out();		//设置为输出模式
	DHT11_Low();				//拉低总线，并保持18-30ms
	Delay_ms(20);
	DHT11_High();				//拉高总线，并延迟10-35us
	Delay_us(30);
	DHT11_Init_In();		//设置为输入模式
}

/**
 * 检查DHT11是否存在
 */
uint8_t DHT11_Check(){
	uint16_t timeout=30;
	while(DHT11_GPIO_Read()==SET && timeout){			//等待DHT11响应
		timeout--;
		Delay_us(1);
	}
	if(!timeout){
		return 0;
	}
	
	timeout=100;
	while(DHT11_GPIO_Read()==RESET && timeout){		//DHT11拉低总线保持78-88us，等待其拉高总线
		timeout--;
		Delay_us(1);
	}
	if(!timeout){
		return 0;
	}
	
	timeout=100;
	while(DHT11_GPIO_Read()==SET && timeout){			//DHT11拉高总线保持80-92us，
		timeout--;																	//等待其再次拉低总线后发送数据
		Delay_us(1);
	}
	if(!timeout){
		return 0;
	}
	return 1;
}

uint8_t DHT11_ReadBit(){
	while(DHT11_GPIO_Read()==RESET);		//读数据开始后等待DHT11拉高总线
	Delay_us(50);												//拉高总线持续23-27us表示0，持续68-74us表示1
	uint8_t bit=DHT11_GPIO_Read();			//延迟50us后若是低电平则为0，否则为1
	while(DHT11_GPIO_Read()==SET);			//等待DHT11拉低总线，准备下一位数据读取
	return bit;
}

uint8_t DHT11_ReadByte(){
	uint8_t dat=0;
	for(int i=0;i<8;i++){
		dat <<= 1;
		dat |= DHT11_ReadBit();
	}
	return dat;
}

/**
 * 读取DHT11数据，成功返回1，否则返回0
 */
uint8_t DHT11_ReadData(float *humi,float *temp){
	uint8_t buf[5];
	DHT11_Init();
	if(DHT11_Check()){
		for(int i=0;i<5;i++){
			buf[i]=DHT11_ReadByte();
		}
		//数据校验
		if(buf[4]==(buf[0]+buf[1]+buf[2]+buf[3])){
			*humi=buf[0]+buf[1]/10.0;
			*temp=buf[2]+buf[3]/10.0;
			return 1;
		}
	}
	return 0;
}

